#pragma once
/*
服务端配置信息模块
该模块的设计主要采用懒汉模式来设计
主要有以下信息:
1. 服务端bind的IP
2. 服务端bind的port
3. 热点判断时间(根据该时间来判断已备份文件是否是热点文件)
4. 文件下载请求的url前缀(请求路径的前缀是这个路径的时候,那么认为客户端发送过来的是一个下载请求)
5. 压缩包后缀名
6. 备份文件存放路径
7. 非热点文件存放路径(压缩文件存放路径)
8.存放备份文件信息的文件的路径(这里可以考虑扩展为数据库来存储文件信息)

*/
#include <mutex>
#include "util.hpp"
//配置文件相关
#define CONFIG_PATH "./cloud.json"
#define SERVER_IP "serverIp"
#define SERVER_PORT "serverPort"
#define HOT_TIME "hotTime"
#define URL_PREFIX "urlPrefix"
#define SUFFIX_NAME "suffixName"
#define BACKUP_FILE_PATH "backupFilePath"
#define COMPRESS_FILE_PATH "compressFilePath"
#define USERNAME "userName"
#define PASSWORD "password"
#define DATABASE "database"
#define USER_TABLE_NAME "userTableName"
#define HOST "host"
#define PORT "port"

namespace Cloud
{
    class Config
    {
    public:
        // 获取单例对象
        static Config &getInstance();

        // 获取配置文件的各个属性
        const std::string &serverIp() const
        {
            return _serverIp;
        };
        const uint16_t &serverPort() const
        {
            return _serverPort;
        };
        const time_t &hotTime() const
        {
            return _hotTime;
        };
        const std::string &urlPrefix() const
        {
            return _urlPrefix;
        };
        const std::string &suffixName() const
        {
            return _suffixName;
        };
        const std::string &backupFilePath() const
        {
            return _backupFilePath;
        };
        const std::string &compressFilePath() const
        {
            return _compressFilePath;
        };
        const std::string &userTableName() const
        {
            return _userTableName;
        }
  const std::string &userName() const
        {
            return _userName;
        }  const std::string &password() const
        {
            return _password;
        }  const std::string &database() const
        {
            return _database;
        }  const std::string &host() const
        {
            return _host;
        }  const uint16_t &port() const
        {
            return _port;
        }
    private:
        Config() = default;
        Config(const Config &);
        Config(Config &&);

    private:
        static Config *_ptr;
        static std::mutex _mux;

    private:
        //服务器配置相关
        std::string _serverIp;
        uint16_t _serverPort;
        time_t _hotTime;
        std::string _urlPrefix;
        std::string _suffixName;
        std::string _backupFilePath;
        std::string _compressFilePath;
        //数据库配置相关
        std::string _userName;
        std::string _password;
        std::string _database;
        std::string _userTableName;
        std::string _host;
        uint16_t _port;
    };
    // 完成静态成员初始化
    Config *Config ::_ptr = nullptr;
    std::mutex Config::_mux;
    Config &Config::getInstance()
    {
        if (_ptr == nullptr)
        {
            std::unique_lock<std::mutex> locker(_mux);
            if (_ptr == nullptr)
            {
                // 完成单例对象的创建
                // 注意这里一定一定不要立刻马上就给_ptr赋值，一定要将配置项加载完毕过后再赋值!!!!!
                // 避免，我们在_ptr赋完值过后，还没开始加载配置文件之前，又有线程来了会直接发现_ptr不为null,直接返回了，这是不合理的！虽然对象已经创建
                // 但是还没完成配置文件的加载！
                Config *ptr = (new Cloud::Config());
                // 完成单例对象的初始化
                // 1. 从配置文件中读取信息
                Json::Value root;
                std::fstream fin(CONFIG_PATH, std::fstream::in);
                if (!JsonUtil::parseFromIstream(fin, &root))
                    exit(-1);
                ptr->_serverIp = root[SERVER_IP].asString();
                ptr->_serverPort = root[SERVER_PORT].asUInt();
                ptr->_hotTime = root[HOT_TIME].asInt64();
                ptr->_urlPrefix = root[URL_PREFIX].asString();
                ptr->_suffixName = root[SUFFIX_NAME].asString();
                ptr->_backupFilePath = root[BACKUP_FILE_PATH].asString();
                ptr->_compressFilePath = root[COMPRESS_FILE_PATH].asString();
                ptr->_userName=root[USERNAME].asString();
                ptr->_password=root[PASSWORD].asString();
                ptr->_database=root[DATABASE].asString();
                ptr->_userTableName=root[USER_TABLE_NAME].asString();
                ptr->_host=root[HOST].asString();
                ptr->_port=root[PORT].asUInt();

                _ptr = ptr;
            }
        }
        return *_ptr;
    }
}
